package com.gupao.javavip.spring.processor;

import com.gupao.javavip.test.other.OtherService;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.stereotype.Component;

import java.beans.Introspector;

@Component
@CommonsLog
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myService");
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        propertyValues.addPropertyValue("name", "testName");


        log.info("beanFactory.containsBeanDefinition(\"otherService\"):" + beanFactory.containsBeanDefinition("otherService"));
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        log.info("registry.containsBeanDefinition(\"otherService\"):" + registry.containsBeanDefinition("otherService"));

        if (!registry.containsBeanDefinition("otherService")) {
            AbstractBeanDefinition definition = BeanDefinitionBuilder
                    .genericBeanDefinition(OtherService.class)
                    .getBeanDefinition();

            //在这里，我们可以给该对象的属性注入对应的实例。
            //比如mybatis，就在这里注入了dataSource和sqlSessionFactory，
            // 注意，如果采用definition.getPropertyValues()方式的话，
            // 类似definition.getPropertyValues().add("interfaceType", beanClazz);
            // 则要求在FactoryBean（本应用中即ServiceFactory）提供setter方法，否则会注入失败
            // 如果采用definition.getConstructorArgumentValues()，
            // 则FactoryBean中需要提供包含该属性的构造方法，否则会注入失败
//            definition.getConstructorArgumentValues().addGenericArgumentValue(OtherService.class);

            //设置字段属性值
            definition.getPropertyValues().add("name", "testName");

            //注意，这里的BeanClass是生成Bean实例的工厂，不是Bean本身。
            // FactoryBean是一种特殊的Bean，其返回的对象不是指定类的一个实例，
            // 其返回的是该工厂Bean的getObject方法所返回的对象。
//            definition.setBeanClass(ServiceFactory.class);

            //注册，类名首字母小写
            String name = Introspector.decapitalize(OtherService.class.getSimpleName());
            registry.registerBeanDefinition(name, definition);
            log.info("已注册：" + name);
        }
    }
}
